package sis.studentinfo;

import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.logging.*;

public class Student {

    final static Logger logger = Logger.getLogger(Student.class.getName());
    private static String invalidInStateSetErrorMsg;
    static final int CREDITS_REQUIRED_FOR_FULL_TIME = 12;
    private static State IN_STATE = State.CO;
    private Name studentName;
    private int credits;
    private State state;
    private List<Grade> grades = new ArrayList<Grade>();
    private long studentID;
    private GradingStrategy gradingStrategy =
            new RegularGradingStrategy();

   

    public Student(Name name, State state) {
        ValidateUtil.checkNullEmpty(new SimpleEntry("name", name));
        this.studentName=name;
        this.setState(state);
        credits = 0;
        setStudentID();
    }

    public Student(Student student) {
        ValidateUtil.checkNullEmpty(new SimpleEntry("student", student));
        studentName=new Name(student.getFullName());
        credits = student.credits;
        state = student.state;
        Collections.copy(grades, student.grades);
        gradingStrategy = student.gradingStrategy;
        studentID = student.studentID;
    }

    public String getFirstName() {
        return studentName.getFirstName();
    }

    public String getMiddleName() {
        return studentName.getMiddleName();
    }

    public String getLastName() {
        return studentName.getLastName();
    }

    private void setStudentID() {
        studentID = UUID.randomUUID().getMostSignificantBits();
    }

    public long getStudentID() {
        return studentID;
    }

    public static void setStateForIN_STATEStatus(State state) {
        ValidateUtil.checkNullEmpty(new SimpleEntry("state", state));
        if (state == State.UNKNOWN || state == State.INTERNATIONAL) {
            invalidInStateSetErrorMsg = state + "is not valid to recive IN_STATE status";
            logger.info(invalidInStateSetErrorMsg);
            throw new IllegalArgumentException(invalidInStateSetErrorMsg);
        }
        IN_STATE = state;
    }

    public static State getStateForIN_STATEStatus() {
        return IN_STATE;
    }

    public String getFullName() {
        return studentName.getFullName();
    }

    boolean isFullTime() {
        return credits >= CREDITS_REQUIRED_FOR_FULL_TIME;
    }

    int getCredits() {
        return credits;
    }

    void addCredits(int credits) {
        this.credits += credits;
    }

    boolean isInState() {
        return state == Student.IN_STATE;
    }

    void setState(State state) {
        ValidateUtil.checkNullEmpty(new SimpleEntry("state", state));
        this.state = state;
    }

    void addGrade(Grade grade) {
        ValidateUtil.checkNullEmpty(new SimpleEntry("grade", grade));
        grades.add(grade);
    }

    double getGpa() {
        if (grades.isEmpty()) {
            return 0.0;
        }
        double total = 0.0;
        for (Grade grade : grades) {
            total += gradingStrategy.getGradePointsFor(grade);
        }
        return total / grades.size();
    }

    void setGradingStrategy(GradingStrategy gradingStrategy) {
        ValidateUtil.checkNullEmpty(new SimpleEntry("gradingStrategy", gradingStrategy));
        this.gradingStrategy = gradingStrategy;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Student)) {
            return false;
        }
        return ((Student) o).studentID == this.studentID;
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + (int) studentID;
        return result;
    }
    static String getInvalidInStateSetErrorMsg()
    {
        return invalidInStateSetErrorMsg;
    }
}